﻿#region [WindowsPhone UsingStatements]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using WP7_XNA_Accelerometer_Simulator.GameObjects.SuperClasses;
using WP7_XNA_Accelerometer_Simulator.Utils.GameInfo;
using WP7_XNA_Accelerometer_Simulator.Utils.Accelerometer;
using WP7_XNA_Accelerometer_Simulator.Utils.Rotation;
#endregion

namespace WP7_XNA_Accelerometer_Simulator.GameObjects.GameModels
{
    /// <summary>
    /// This class represents the Windows phone 7
    /// </summary>
    public class WindowsPhone : GameObject3D
    {
        #region [WindowsPhone Fields]
        private readonly Vector3 _originalTopEdgeNormal = new Vector3(0, 0, 1);
        private readonly Vector3 _originalFrontEdgeNormal = new Vector3(0, 1, 0);
        private readonly Vector3 _originalRightEdgeNormal = new Vector3(1, 0, 0);
        private Vector3 _currentTopEdgeNormal;
        private Vector3 _currentFrontEdgeNormal;
        private Vector3 _currentRightEdgeNormal;
        private float _accelX;
        private float _accelY;
        private float _accelZ;
        #endregion

        #region [WindowsPhone Constructor]
        /// <summary>
        /// WindowsPhone Contructor
        /// </summary>
        public WindowsPhone()
        {
            Scale = new Vector3(2F, 2F, 2F);
            Position = new Vector3(0, 0, 0);
            Rotation = Vector3.Zero;
            _currentTopEdgeNormal = _originalTopEdgeNormal;
            _currentFrontEdgeNormal = _originalFrontEdgeNormal;
            _currentRightEdgeNormal = _originalRightEdgeNormal;
        }
        #endregion

        #region [WindowsPhone LoadContent and Draw Methods]
        public override void LoadContent(ContentManager content)
        {
            GameModel = content.Load<Model>(GameConstants.WPModelUri);
            base.LoadContent(content);
        }

        public override void Draw(GameTime gameTime)
        {
            Matrix modelRotation = Matrix.CreateFromQuaternion(QuatRotationMatrix);
            Matrix modelPosition = Matrix.CreateTranslation(Position);
            Matrix modelScale = Matrix.CreateScale(Scale);

            foreach (ModelMesh mesh in GameModel.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;
                    effect.World =  modelScale * modelRotation * modelPosition;
                    effect.Projection = GameManager.CameraProjectionMatrix;
                    effect.View = GameManager.CameraViewMatrix;
                }
                mesh.Draw();
            }
        }
        #endregion

        #region [WindowsPhone Private/Auxiliary Methods]
        /// <summary>
        /// Updates the windows phone axis normals according to the phone's rotation
        /// </summary>
        private void UpdateNormals()
        {
            Matrix m_rot = Matrix.CreateFromQuaternion(QuatRotationMatrix);
            _currentTopEdgeNormal = Vector3.TransformNormal(_originalTopEdgeNormal, m_rot);
            _currentFrontEdgeNormal = Vector3.TransformNormal(_originalFrontEdgeNormal, m_rot);
            _currentRightEdgeNormal = Vector3.TransformNormal(_originalRightEdgeNormal, m_rot);
        }
        #endregion

        #region [WindowsPhone Public Methods]
        /// <summary>
        /// Calculates the phone's acceleration values
        /// </summary>
        /// <returns>
        /// Acceleration on the X, Y and Z axis
        /// </returns>
        public Vector3 GetAccelValues()
        {
            UpdateNormals();
            Vector3 accelValues =  AccelMath.CalculateAccelValues(_currentRightEdgeNormal, _currentTopEdgeNormal, _currentFrontEdgeNormal);
            return accelValues;
        }

        /// <summary>
        /// See <see cref="GameObject3D.ProcessRotation"/> for more info.
        /// </summary>
        /// <remarks>
        /// Upload Rotation and Acceleration values to the server and process rotation
        /// </remarks>
        public override void  ProcessRotation(RotationUtil.RotationType rotType, float rotDegrees)
        {
            Vector3 accelValues;
            
            accelValues = GetAccelValues();
            GameManager.AccelerometerService.UploadAccelData(accelValues.X, accelValues.Y, accelValues.Z);
            GameManager.AccelerometerService.UploadRotationData(MathHelper.ToDegrees(Rotation.X), 
                                                                MathHelper.ToDegrees(Rotation.Y), 
                                                                MathHelper.ToDegrees(Rotation.Z));

            base.ProcessRotation(rotType, rotDegrees);
        }
        #endregion
    }
}
